package com.rslai.commons.util;

import com.rslai.commons.util.exception.RunException;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 字符串工具类
 * Created by rslai on 2018/12/8.
 */
public class StringUtil {

    /**
     * <p>判断某字符串是否为空，为空的标准是 str==null 或 str.length()==0</p>
     *
     * <pre>
     * StringUtils.isEmpty(null) = true
     * StringUtils.isEmpty("") = true
     * StringUtils.isEmpty(" ") = false //注意在 StringUtils 中空格作非空处理
     * StringUtils.isEmpty("   ") = false
     * StringUtils.isEmpty("bob") = false
     * StringUtils.isEmpty(" bob ") = false
     * </pre>
     *
     * @param str 待检查的字符串
     * @return {@code true} 待检查的字符串是 empty 或 null
     */
    public static boolean isEmpty(String str) {
        return org.apache.commons.lang3.StringUtils.isEmpty(str);
    }

    /**
     * <p>判断某字符串是否非空，等于 !isEmpty(String str)</p>
     *
     * <pre>
     * StringUtils.isNotEmpty(null) = false
     * StringUtils.isNotEmpty("") = false
     * StringUtils.isNotEmpty(" ") = true
     * StringUtils.isNotEmpty("         ") = true
     * StringUtils.isNotEmpty("bob") = true
     * StringUtils.isNotEmpty(" bob ") = true
     * </pre>
     *
     * @param str 待检查的字符串
     * @return {@code true} 待检查的字符串不是 empty 或 null
     */
    public static boolean isNotEmpty(String str) {
        return org.apache.commons.lang3.StringUtils.isNotEmpty(str);
    }

    /**
     * <p>判断某字符串是否为空或长度为0或由空白符(whitespace) 构成</p>
     *
     * <pre>
     * StringUtils.isBlank(null) = true
     * StringUtils.isBlank("") = true
     * StringUtils.isBlank(" ") = true
     * StringUtils.isBlank("        ") = true
     * StringUtils.isBlank("\t \n \f \r") = true   //对于制表符、换行符、换页符和回车符
     * StringUtils.isBlank()   //均识为空白符
     * StringUtils.isBlank("\b") = false   //"\b"为单词边界符
     * StringUtils.isBlank("bob") = false
     * StringUtils.isBlank(" bob ") = false
     * </pre>
     *
     * @param str 待检查的字符串
     * @return {@code true} 待检查的字符串是 null, empty 或 空白符(whitespace)
     */
    public static boolean isBlank(String str) {
        return org.apache.commons.lang3.StringUtils.isBlank(str);
    }

    /**
     * <p>判断某字符串是否不为空且长度不为0且不由空白符(whitespace) 构成，等于 !isBlank(String str)</p>
     *
     * <pre>
     * StringUtils.isNotBlank(null) = false
     * StringUtils.isNotBlank("") = false
     * StringUtils.isNotBlank(" ") = false
     * StringUtils.isNotBlank("         ") = false
     * StringUtils.isNotBlank("\t \n \f \r") = false
     * StringUtils.isNotBlank("\b") = true
     * StringUtils.isNotBlank("bob") = true
     * StringUtils.isNotBlank(" bob ") = true
     * </pre>
     *
     * @param str 待检查的字符串
     * @return {@code true} 待检查的字符串不是 null, empty 或 空白符(whitespace)
     */
    public static boolean isNotBlank(String str) {
        return org.apache.commons.lang3.StringUtils.isNotBlank(str);
    }

    /**
     * <p>去掉字符串两端的控制符(control characters, char &lt;= 32),如果输入为null则返回null</p>
     *
     * <pre>
     * StringUtils.trim(null)          = null
     * StringUtils.trim("")            = ""
     * StringUtils.trim("     ")       = ""
     * StringUtils.trim("abc")         = "abc"
     * StringUtils.trim("    abc    ") = "abc"
     * </pre>

     * @param str 待处理的字符串
     * @return 处理后的字符串
     */
    public static String trim(String str) {
            return org.apache.commons.lang3.StringUtils.trim(str);
    }

    /**
     * <p>去掉字符串两端的控制符(control characters, char &lt;= 32),如果变为null或""，则返回null</p>
     *
     * <pre>
     * StringUtils.trimToNull(null)          = null
     * StringUtils.trimToNull("")            = null
     * StringUtils.trimToNull("     ")       = null
     * StringUtils.trimToNull("abc")         = "abc"
     * StringUtils.trimToNull("    abc    ") = "abc"
     * </pre>
     *
     * @param str 待处理的字符串
     * @return 处理后的字符串
     */
    public static String trimToNull(String str) {
        return org.apache.commons.lang3.StringUtils.trimToNull(str);
    }

    /**
     * <p>去掉字符串两端的控制符(control characters, char &lt;= 32),如果变为null或""，则返回""</p>
     *
     * <pre>
     * StringUtils.trimToEmpty(null)          = ""
     * StringUtils.trimToEmpty("")            = ""
     * StringUtils.trimToEmpty("     ")       = ""
     * StringUtils.trimToEmpty("abc")         = "abc"
     * StringUtils.trimToEmpty("    abc    ") = "abc"
     * </pre>
     *
     * @param str 待处理的字符串
     * @return 处理后的字符串
     */
    public static String trimToEmpty(String str) {
        return org.apache.commons.lang3.StringUtils.trimToEmpty(str);
    }

    /**
     * <p>去掉字符串两端的空白符(whitespace)，如果输入为null则返回null</p>
     *
     * <pre>
     * StringUtils.strip(null)     = null
     * StringUtils.strip("")       = ""
     * StringUtils.strip("   ")    = ""
     * StringUtils.strip("abc")    = "abc"
     * StringUtils.strip("  abc")  = "abc"
     * StringUtils.strip("abc  ")  = "abc"
     * StringUtils.strip(" abc ")  = "abc"
     * StringUtils.strip(" ab c ") = "ab c"
     * </pre>
     *
     * @param str 待处理的字符串
     * @return 处理后的字符串
     */
    public static String strip(String str) {
        return org.apache.commons.lang3.StringUtils.strip(str);
    }

    /**
     * <p>去掉字符串两端的空白符(whitespace)，如果变为null或""，则返回null</p>
     *
     * <pre>
     * StringUtils.stripToNull(null)     = null
     * StringUtils.stripToNull("")       = null
     * StringUtils.stripToNull("   ")    = null
     * StringUtils.stripToNull("abc")    = "abc"
     * StringUtils.stripToNull("  abc")  = "abc"
     * StringUtils.stripToNull("abc  ")  = "abc"
     * StringUtils.stripToNull(" abc ")  = "abc"
     * StringUtils.stripToNull(" ab c ") = "ab c"
     * </pre>
     *
     * @param str 待处理的字符串
     * @return 处理后的字符串
     */
    public static String stripToNull(String str) {
        return org.apache.commons.lang3.StringUtils.stripToNull(str);
    }

    /**
     * <p>去掉字符串两端的空白符(whitespace)，如果变为null或""，则返回""</p>
     *
     * <pre>
     * StringUtils.stripToEmpty(null)     = ""
     * StringUtils.stripToEmpty("")       = ""
     * StringUtils.stripToEmpty("   ")    = ""
     * StringUtils.stripToEmpty("abc")    = "abc"
     * StringUtils.stripToEmpty("  abc")  = "abc"
     * StringUtils.stripToEmpty("abc  ")  = "abc"
     * StringUtils.stripToEmpty(" abc ")  = "abc"
     * StringUtils.stripToEmpty(" ab c ") = "ab c"
     * </pre>
     *
     * @param str 待处理的字符串
     * @return 处理后的字符串
     */
    public static String stripToEmpty(String str) {
        return org.apache.commons.lang3.StringUtils.stripToEmpty(str);
    }

    /**
     * 将字符串转类型解析为日期类型，由于可以将多种格式转换为日期所以会稍慢些，一般用作文件导入
     * parseToDate("2015年5月5日");
     * parseToDate("2015年5月5日 5:15");
     * parseToDate("2015年5月5日 5:15:15");
     * parseToDate("2015/5/5 5:15:15");
     * parseToDate("2015-5-5 5:15:15");
     * parseToDate("2015/5/5 5：15：15");
     * parseToDate("2015.5.5 5：15：15");
     * @param str 待解析字符串
     * @return Date对象
     * @throws RunException RunException
     */
    public static Date parseToDate(String str) throws RunException {
        Date ret;
        str = str.replace('.','/').replace('年','/').replace('-','/').replace('月','/').replace('日',' ').replace('：',':').replace("  "," ");
        try {
            Matcher shortDate = Pattern.compile("[0-9]{2,4}/[0-9]{1,2}/[0-9]{1,2}").matcher(str);
            Matcher longDate = Pattern.compile("[0-9]{2,4}/[0-9]{1,2}/[0-9]{1,2} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}").matcher(str);
            Matcher longDateNotSecond = Pattern.compile("[0-9]{2,4}/[0-9]{1,2}/[0-9]{1,2} [0-9]{1,2}:[0-9]{1,2}").matcher(str);

            if (shortDate.matches()) {
                ret = (new SimpleDateFormat("yyyy/MM/dd")).parse(str);
            } else if (longDate.matches()) {
                ret = (new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")).parse(str);
            } else if (longDateNotSecond.matches()) {
                ret = (new SimpleDateFormat("yyyy/MM/dd HH:mm")).parse(str);
            } else {
                throw new RunException("格式错误，无法将字符串“" + str + "”转换位日期时间类型！");
            }
        } catch (ParseException e) {
            throw new RunException("格式错误，无法将字符串“" + str + "”转换位日期时间类型！");
        }
        return ret;
    }

    /**
     * 将 Date 类型转为 String，如果为 2015/5/5 00:00:00 则返回 2015/5/5
     * @param date 日期
     * @return 返回年月日字符串，例2015/5/5
     * @throws RunException RunException
     */
    public static String parseToString(Date date) throws RunException {
        DateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        return format.format(date).replace(" 00:00:00", "");
    }

    /**
     * 将 Date 类型转为 String，如果为 2015/5/5 则返回 2015/5/5 00:00:00
     * @param date Date对象
     * @return 返回年月日时分秒，例 2015/5/5 00:00:00
     * @throws RunException RunException
     */
    public static String parseToLongString(Date date) throws RunException {
        DateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        return format.format(date);
    }

    /**
     * 截取字符串 - 根据正则表达式
     * @param str 待截取字符串
     * @param regex 正则表达式
     * @return 没匹配到正则表达式返回 null，否则返回 截取到的字符串
     */
    public static String subStringByRegex(String str, String regex) {
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(str);
        if (matcher.find()) {
            return matcher.group(1);
        } else {
            return null;
        }
    }

    /**
     * 压缩 JSON 字符串
     * @param json 需要被压缩的JSON字符串
     * @return 压缩后的JSON字符串
     */
    public static String compressJson(String json) {
        if (json == null || "".equals(json)) {
            return "";
        }

        StringBuilder sb = new StringBuilder();
        boolean isKeyOrValue = false; // 是 key 或 value(也就是被 " 号包裹的内容，" 号包裹中的空格会被保留）
        int length = json.length();
        for (int i = 0; i < length; i++) {
            char currentChar = json.charAt(i);
            if (currentChar == '"') {
                isKeyOrValue = !isKeyOrValue;
            }
            if (!isKeyOrValue && (currentChar == ' ' || currentChar == '\t' || currentChar == '\r' || currentChar == '\n')) {
                continue;
            }
            sb.append(currentChar);
        }
        return sb.toString();
    }

}
